
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** @author  Michael E. Cotterell
 *  @version 1.0
 *  @date    Wed Aug  21 20:08:06 EDT 2013
 *  @see     LICENSE (MIT style license file).
 */

package scalation.coroutine

import scala.collection.mutable.PriorityQueue
import scala.util.continuations._

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** This `Scheduler` trait provides an interface for coroutine schedulers.
 */
trait Scheduler extends Coroutine
{
    /** The currently executing coroutine (execute one at a time).
     */
    protected var _current: Coroutine = null
    
    /** The clock that keep track of the current scheduling time.
     */
    protected var _clock = 0.0
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** The current value of the Scheduler's clock.
     */
    final def clock () = _clock
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Schedule (first time) or reschedule (subsequent times) a coroutine to
     *  execute. 
     *  @param coroutine  the coroutine to be scheduled
     */
    def reschedule (coroutine: Coroutine): Unit

} // Scheduler


//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** This `PriorityScheduler` class provides a coroutine scheduler implementation
 *  that is backed by an instance of the `PriorityQueue [Coroutine]` class.
 */
case class PriorityScheduler () extends Scheduler
{
    
    /** The future event list.
     */
    protected val agenda = PriorityQueue.empty [Coroutine] 
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Implements for Scheduler mixin.
     */
    def reschedule (coroutine: Coroutine) = { agenda += coroutine }
    
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** The scheduler itself is a coroutine and may be thought of as the 
     *  director.  The director iteratively manages the clock and the agenda of 
     *  coroutines until the agenda becomes empty.
     */
    override def run (): Unit @suspendable = 
    {
        while (!agenda.isEmpty) {
            _current = agenda.dequeue ()
            _clock   = _current.actTime
            println("[%.6f] %s RESUMES %s".format (_clock, "Scheduler", _current))
            yieldToCoroutine (_current)
        } // while
    } // run
    
} // PriorityScheduler

